package com.vatata.wae.jsobject.Media;

import static com.google.android.exoplayer2.C.TRACK_TYPE_AUDIO;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.graphics.Rect;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.util.Log;
import android.view.Gravity;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.FrameLayout;

import com.google.android.exoplayer2.DefaultRenderersFactory;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.source.hls.HlsMediaSource;
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
import com.google.android.exoplayer2.upstream.FileDataSource;
import com.google.android.exoplayer2.util.Util;
import com.google.android.exoplayer2.video.VideoListener;
import com.vatata.wae.jsobject.UI.IView;
import com.vatata.wae.jsobject.WAE.MessageManager;

import java.lang.reflect.Field;

public class VideoPlayer3 extends IView {
//    private static int logEnabled = -1;
//    private static final String VTAG = "VideoPlayerKTV";
//
//    public static void log(String msg) {
//        if (logEnabled == -1) {
//            logEnabled = 0;
//            try {
//                File logVideoPlayer = new File("/sdcard/tva/log.videoplayer");
//                if (logVideoPlayer.exists())
//                    logEnabled = 1;
//            } catch (Exception e) {
//            }
//            if (WaeWebChromeClient.isOutputConsoleMessage) {
//                logEnabled = 1;
//            }
//            Log.d(VTAG, "logEnabled: " + logEnabled);
//        }
//        if (logEnabled == 0)
//            return;
//
//        Log.d(VTAG, msg);
//    }

    public void destory() {
        log("VideoPlayer destroy!");
        if (player != null) {
            _runOnPlayer(new Runnable() {
                @Override
                public void run() {
                    if ( player.isPlaying() ) {
                        player.stop(true);
                    }
                    player.release();
                    player = null;
                }
            });
        }
        super.destory();
    }

    boolean _has_destroied() {
        if (view == null || view.activity == null) return true;
        return false;
    }

    void _runOnPlayer(Runnable r) {
        view.activity.runOnUiThread(r);
//		playerHandler.post(r);
    }

    void _runOnUI(Runnable r) {
        view.activity.runOnUiThread(r);
    }

    @Override
    public void _create() {
        _runOnPlayer(new Runnable() {

            @Override
            public void run() {
                try {
                    iview = initVideoView();

                } catch (Exception e) {
                    log("initVideoView meet : " + e.getLocalizedMessage());
                    e.printStackTrace();
                    return;
                }
                if (iview == null) return;

                MessageManager.sendMessage(view, objectId, "Created");
            }
        });
    }

    SimpleExoPlayer player = null;
    Player.Listener eventListener = null;
    boolean playWhenReady = true;
//            new DefaultBandwidthMeter();
    DefaultTrackSelector trackSelector;

    String userAgent = "";

    boolean hasPrePrared = false;

    SurfaceView mSurfaceView;

    private View initVideoView() {
        mSurfaceView = new SurfaceView( view.activity );
        mSurfaceView.setFocusable(false);
        mSurfaceView.setFocusableInTouchMode(false);

        SurfaceHolder holder = mSurfaceView.getHolder();
//	    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
//	    holder.setFormat(PixelFormat.RGBX_8888);

        holder.addCallback( new SurfaceHolder.Callback(){

            @Override
            public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
                                       int arg3) {
                // TODO Auto-generated method stub

            }

            @Override
            public void surfaceCreated(SurfaceHolder holder ) {
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder arg0) {
                // TODO Auto-generated method stub

            }} );

        mSurfaceView.setZOrderMediaOverlay(true);
        mSurfaceView.setZOrderOnTop(false);

        FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(100, 100);
        view.activity.getRootView().addView(mSurfaceView, lp);

        if (player == null) {
            userAgent = Util.getUserAgent(view.activity, "TVA EVideoPlayer");

//            AdaptiveTrackSelection.Factory()
            AdaptiveTrackSelection.Factory trackSelectionFactory = new AdaptiveTrackSelection.Factory();

            trackSelector = new DefaultTrackSelector( view.activity, trackSelectionFactory);
            DefaultRenderersFactory renderersFactory =
                    new DefaultRenderersFactory(view.activity);
//            player = ExoPlayerFactory.newSimpleInstance(renderersFactory, trackSelector);

//            DefaultRenderersFactory renderersFactory =
//                    new DefaultRenderersFactory(view.activity, DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER);
//            player = ExoPlayerFactory.newSimpleInstance(renderersFactory, trackSelector);

//            player = ExoPlayerFactory.newSimpleInstance( view.activity, renderersFactory, trackSelector, new DefaultLoadControl());
//            player.addListener(  );
            SimpleExoPlayer.Builder builder = new SimpleExoPlayer.Builder( view.activity.getApplicationContext() );
            builder.setTrackSelector( trackSelector );
            player = builder.build();

            log("Videoplayer3 create get player: " + player );

            eventListener = new Player.Listener(){

                public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
                    switch ( playbackState) {
                        case Player.STATE_READY:
                            log("STATE_READY"  );

                            if ( hasPrePrared == false ) {
                                hasPrePrared = true;
                                MessageManager.sendMessage(view, objectId,
                                        "Prepared",
                                        url, getDuration(), getVolume() );
                            }

                            MessageManager.sendMessage(view, objectId, "BufferingUpdate",
                                    url, 100 , "ready");
                            break;
                        case Player.STATE_BUFFERING:
                            log("STATE_BUFFERING"  );
                            MessageManager.sendMessage(view, objectId, "BufferingUpdate",
                                    url, 0 , "buffering");
                            break;
                        case Player.STATE_ENDED:
                            log("STATE_ENDED"  );
                            MessageManager.sendMessage(view, objectId,
                                    "Completion", url);
                            break;
                    }
                }

                public void onPlayerError(ExoPlaybackException error) {
                    log("onPlayError: " + error.toString() );
//                    Toast.makeText(view.activity, error.toString() , Toast.LENGTH_LONG ).show();
                    MessageManager.sendMessage(view, objectId,
                            "Error", url, error.toString() );
                }
            };
            player.addListener( eventListener );

            player.addVideoListener(new VideoListener() {
                @Override
                public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
                    log("video size change " + width + "x" + height);
                }

                @Override
                public void onSurfaceSizeChanged(int width, int height) {
                    log("sufacesize change: " + width + "x" + height );
                }

                @Override
                public void onRenderedFirstFrame() {
                    log("render start ...");
                }
            });
        }

        player.setVideoSurfaceView( mSurfaceView );
        player.setPlayWhenReady(playWhenReady);

        return mSurfaceView;
    }


    public static boolean force1080pfullscreen = false;

    boolean isFullscreen = false;

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    public void setFullScreen() {
        if ( iview == null ) {
            log("setFullscreen but iview is null!");
            return;
        }
        log("setFullScreen isFullscreen : " + isFullscreen + " isvisbile : " + iview.getVisibility() );
        if (isFullscreen == true &&iview.getVisibility() == View.VISIBLE  ) {
            return;
        }

        if ( force1080pfullscreen == true ) {
            this.move(0,0,1920,1080);
            isFullscreen = true;
            return;
        }

        _runOnUI(new Runnable() {

            @Override
            public void run() {
                if ( iview.getVisibility() != View.VISIBLE ) {
                    iview.setVisibility(View.VISIBLE );
                }

//                DisplayMetrics metrics = new DisplayMetrics();
//                view.activity.getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
//                final int nw = metrics.widthPixels;
//                final int nh = metrics.heightPixels;

                int nw = FrameLayout.LayoutParams.MATCH_PARENT;
                int nh = FrameLayout.LayoutParams.MATCH_PARENT;

//                nw = 1920;
//                nh = 1080;

                log("setFullScreen: " + nw + "x" + nh);
                FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) iview.getLayoutParams();
                if (lp == null) {
                    lp = new FrameLayout.LayoutParams(nw, nh);
                }
                lp.leftMargin = 0;
                lp.topMargin = 0;
                lp.height = nh;
                lp.width = nw;

                iview.setLayoutParams(lp);
                iview.setScaleX(1.0f);
                iview.setScaleY(1.0f);

                if ( iview.getVisibility() != View.VISIBLE ) {
                    iview.setVisibility(View.VISIBLE);
                }

//                mSurfaceView.getHolder().setSizeFromLayout();
                isFullscreen = true;
            }
        });
    }

    public void keepScreenOn() {
        view.activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
    }

    String url = null;

    public void setDataSource(final String murl) {
        log("setDataSource " + murl );
//        log("setDataSource when playerview is getVisibility " + iview.getVisibility() );
        if (_has_destroied()) {
            log("setDataSource since mediaplayer has be destoried!");
            return;
        }

        if( iview == null ) {
            Handler h = new Handler();
            h.postDelayed(new Runnable() {
                @Override
                public void run() {
                    setDataSource(murl);
                }
            }, 1000 );
        }

        if ( iview.getVisibility() != View.VISIBLE ) {
            view.activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    iview.setVisibility(View.VISIBLE);
                }
            });
        }
        url = murl;

        Uri uri = Uri.parse(murl);
        MediaSource mediaSource = null;
        log("VideoPlayer3 try play " + murl );
        if (murl.contains(".m3u8")) {
            DefaultBandwidthMeter BANDWIDTH_METER = DefaultBandwidthMeter.getSingletonInstance( view.activity );

            DefaultDataSourceFactory mediaDataSourceFactory = new DefaultDataSourceFactory(
                    view.activity, BANDWIDTH_METER,
                    new DefaultHttpDataSourceFactory(userAgent, BANDWIDTH_METER));

            mediaSource = new HlsMediaSource.Factory(mediaDataSourceFactory)
                    .createMediaSource(uri);
//            mediaSource = new HlsMediaSource.Factory(mediaDataSourceFactory)
//                    .createMediaSource(uri, null, null);
        } else if ( murl.contains("file://")  ) {
            FileDataSource fileDataSource = new FileDataSource();
            try {
//                fileDataSource.open( new DataSpec( uri ));
//                DataSource.Factory factory = new DataSource.Factory() {
//                    @Override
//                    public DataSource createDataSource() {
//                        return fileDataSource;
//                    }
//                };

                DefaultBandwidthMeter mDefaultBandwidthMeter =new DefaultBandwidthMeter();
                DefaultDataSourceFactory upstreamFactory =new DefaultDataSourceFactory(view.activity.getApplicationContext(),
                        mDefaultBandwidthMeter,new DefaultHttpDataSourceFactory(userAgent,null,15000,15000,true));
                mediaSource = new ProgressiveMediaSource.Factory(upstreamFactory).
                        createMediaSource(uri);

//                mediaSource = new ExtractorMediaSource(fileDataSource.getUri(),
//                        factory, new DefaultExtractorsFactory(), null, null);
            } catch ( Exception e) {
                e.printStackTrace();
            }
        }
        else {
//            log("VideoPlayer3 try play !!! " + murl );
//            mediaSource = new ProgressiveMediaSource.Factory(
//                    new DefaultHttpDataSourceFactory(userAgent)).
//                    createMediaSource(uri);

            mediaSource = new ProgressiveMediaSource.Factory(
                    new DefaultHttpDataSourceFactory(userAgent, 15000, 15000, true)).
                    createMediaSource(uri);

//            log("VideoPlayer3 try play !!!111 " + murl );
        }

        mappedTrackInfo = null;
        hasPrePrared = false;

        final MediaSource mediaSource2 = mediaSource;

        view.activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                player.prepare(mediaSource2);
                player.setPlayWhenReady(true);

//                MessageManager.sendMessage(view, objectId,
//                        "Prepared",
//                        url, getDuration(), getVolume() );
            }
        });
    }

    public void start() {
        if (_has_destroied()) return;

        view.activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                player.setPlayWhenReady(true);
                player.getPlaybackState();
            }
        });
    }

    public void pause() {
        if (_has_destroied()) return;
        view.activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                player.setPlayWhenReady(false);
                player.getPlaybackState();
            }
        });
    }

    public void stop() {
        if (_has_destroied()) return;
        player.stop();
//        log("stop and hide");
//        this.hide();
    }

    public void seekTo( final int msec ) {
        if (_has_destroied()) return;
        _runOnPlayer(new Runnable() {
            @Override
            public void run() {
                player.seekTo( msec );
            }
        });
//        player.seekTo( msec );
    }

    public boolean isPlaying() {
        int state = player.getPlaybackState();
        if ( player.getPlayWhenReady() == true && state == Player.STATE_READY ) return true;
        return false;
    }

    public int getCurrentPosition() {
        if ( _has_destroied() ) return -1;

        view.activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if( player == null ) return;
                float d = player.getDuration();
                float t = player.getCurrentPosition();
                MessageManager.sendMessage(view, objectId,
                        "Play", d, t );
            }
        });

        return 0;
//        return (int) player.getCurrentPosition();
    }
    public int getDuration() {
        if ( _has_destroied() ) return -1;
//        return (int) player.getDuration();
        view.activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if( player == null ) return;
                float d = player.getDuration();
                float t = player.getCurrentPosition();
                MessageManager.sendMessage(view, objectId,
                        "Play", d, t );
            }
        });

        return 0;
    }

    public float getVolume() {
        int cvol= view.activity.application.audioManager
                .getStreamVolume(AudioManager.STREAM_MUSIC);

        int mvol= view.activity.application.audioManager
                .getStreamMaxVolume(AudioManager.STREAM_MUSIC);

        return cvol *1.0f / mvol;
    }


    public void setVolume( float vol ) {
        int mvol= view.activity.application.audioManager
                .getStreamMaxVolume(AudioManager.STREAM_MUSIC);
        int cvol =(int)( mvol * vol);
        view.activity.application.audioManager
                .setStreamVolume(AudioManager.STREAM_MUSIC, cvol, 0);
    }


    public void setMute( boolean isMute ) {
        view.activity.application.audioManager.setStreamMute(AudioManager.STREAM_MUSIC, isMute);
    }


    public void setStereoVolume( float l, float r ) {
        try {
            log("try use refelct to get private member audiotrack!");
            Field audiotrackField = player.getClass().getDeclaredField("keepSessionIdAudioTrack");
            audiotrackField.setAccessible(true);
            AudioTrack audioTrack = (AudioTrack) audiotrackField.get(player);
            log("get audiotrack : " + audioTrack );
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                audioTrack.setStereoVolume( l , r );
                log("set stereovolme ok!");
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }


    float speed = 1f;
    float pitch = 1f;
    public void setPlaySpeed( float speed ) {
        log("setPlaySpeed :" + speed );
        this.speed = speed;
        PlaybackParameters param = new PlaybackParameters(speed, pitch);
        player.setPlaybackParameters(param);
    }

    public void setPlayPitch( float pitch ) {
        log("setPlayPitch: " + pitch);
        if (_has_destroied()) return;
        this.pitch = pitch;
        view.activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                PlaybackParameters param = new PlaybackParameters(speed, pitch);
                player.setPlaybackParameters(param);
            }
        });
    }

    public void setPlayEffects( float speed, float pitch ) {
        this.speed = speed;
        this.pitch = pitch;
        view.activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                PlaybackParameters param = new PlaybackParameters(speed, pitch);
                player.setPlaybackParameters(param);
            }
        });
    }

    public float getSpeed() {
        return speed;
    }
    public float getPitch() {
        return pitch;
    }



    //    ArrayList<String> langList = new ArrayList<String>();
    MappingTrackSelector.MappedTrackInfo mappedTrackInfo = null;
    int rederIdx = -1;
    public int getAudioTrack() {
        if ( player == null ) return -1;

        mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo();
        if ( mappedTrackInfo== null ) return -1;

        int c = mappedTrackInfo.getRendererCount();
        for( int i=0; i<c; i++ ) {
            int type = mappedTrackInfo.getRendererType(i);
            if ( type != TRACK_TYPE_AUDIO ) continue;

            rederIdx = i;
//            log("found TRACK_TYPE_AUDIO  idx is  " + i );
            int total = 0;
            TrackGroupArray trackGroupList = mappedTrackInfo.getTrackGroups(i);
            for( int j = 0; j<trackGroupList.length; j++  ) {
                TrackGroup trackGroup = trackGroupList.get(j);
//                log("found TrackGroup " + j + " : " + trackGroup );
                for(int k =0; k<trackGroup.length; k++ ) {
                    Format format = trackGroup.getFormat(k);
                    log("get format " + format );
                    String mimeType = format.sampleMimeType;
                    log("getAudioTrack: trackGroup: " + trackGroup.toString() );
                    log("getAudioTrack: format    : " + format.toString() );
                    log("getAudioTrack: format.mimeType    : " + format.sampleMimeType );
                    log("getAudioTrack: format.id    : " + format.id );
                    log("getAudioTrack: format.lang    : " + format.language );

//                    format.stereoMode
                    total ++;
                }
            }
            return total;
        }

        return -1;
    }

    public void setAudioTrackByIdx( final int idx ) {
        if ( player == null )
            return;

        if ( trackSelector == null )
            return;

        if ( mappedTrackInfo == null )
            getAudioTrack();
        if ( mappedTrackInfo == null )
            return;

        int c = getAudioTrack();
        if (  c < 0 || idx >= c ) {
            return;
        }

        DefaultTrackSelector.ParametersBuilder parametersBuilder = trackSelector.buildUponParameters().setSelectionOverride(
                rederIdx,
                mappedTrackInfo.getTrackGroups(rederIdx),
                new DefaultTrackSelector.SelectionOverride(idx, 0)
        );

        trackSelector.setParameters( parametersBuilder );

//        if ( idx < 0 || idx >= langList.size() ) {
//            log("setAudioTrackByIdx " + idx + " ? max size: " + langList.size() );
//            return;
//        }
//
//        String lang = langList.get(idx);
//        log("setAudioTrackByName " + lang );
//
//        new DefaultTrackSelector.SelectionOverride(0, 0);
//
//        trackSelector.setParameters( trackSelector.getParameters().buildUpon().setPreferredAudioLanguage(lang));
    }

    public void setOnCompletionListener() {
        log("unused setOnCompletionListener ");
    }

    public void setOnBufferingUpdateListener() {
        log("unused setOnBufferingUpdateListener ");
    }

    public void setOnErrorListener() {
        log("unused setOnErrorListener ");
    }

    public void BufferSwitch(int bf){
        log("BufferSwitch unused !");
    }
    public void setLocation(final int width, final int height, final int x,
                            final int y) {
        log("setLcation: " + width + "x" + height );
        this.move(x,y,width,height);
        this.isFullscreen = false;
    }

    public void move( final int x, final int y, final int width, final int height ) {
        view.activity.runOnUiThread(new Runnable() {

            @SuppressLint("NewApi")
            @Override
            public void run() {
                if ( iview == null )
                    return;

                Rect outRect = new Rect();
                view.activity.getRootView().getWindowVisibleDisplayFrame(outRect);
                int w = outRect.width() - view.activity.xpadding * 2;

                nx = x;
                ny= y;
                nw = width;
                nh = height ;

                if ( force_1080p == true ) {
                    float ratio = w * 1.0f / 1920;
                    Log.d("UI_IView", " window metrics : " + outRect.width() + "x" + outRect.height() + " ratio: "  + ratio );

                    nx = (int) (x * ratio);
                    ny = (int) (y * ratio);

                    nw = (int) (width * ratio);
                    nh = (int) (height* ratio);
                }

                Log.d("IView", "move window orig : " + width + "x" + height + ":" + x + ":" +y + "  move window to : " + nw + "x" + nh + ":" + nx + ":" +ny );
                MessageManager.sendMessage(view, objectId, "Move", nx, ny, nw, nh);

                if (width <= 0 || height < 0) {
                    iview.setVisibility(View.GONE);
                } else {
                    FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) iview.getLayoutParams();
                    if ( lp == null ) {
                        lp = new FrameLayout.LayoutParams( nw, nh );
                    }
                    lp.gravity = Gravity.LEFT;

                    lp.leftMargin = nx;
                    lp.topMargin = ny;
                    lp.height = nh;
                    lp.width = nw;

                    iview.setLayoutParams( lp );
                }
            }
        });
    }

}

